#!/bin/bash

set -e

# 加载路径配置
source "$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)/../config/paths.conf"

# 全局变量，用于控制监控状态
MONITOR_RUNNING=true

# 改进的信号处理函数
cleanup() {
    if [ "$MONITOR_RUNNING" = "true" ]; then
        echo "接收到终止信号，正在停止监控..."
        MONITOR_RUNNING=false
    fi
}

# 注册信号处理 - 使用更精确的信号
trap cleanup TERM INT

TIMESTAMP=$(date +%Y%m%d_%H%M%S)
INTERFACE="any"
DURATION=${1:-7200}  # 默认2小时
MAX_DISK_USAGE=85    # 最大磁盘使用率百分比
MAX_LOG_SIZE=500     # 单个日志文件最大大小(MB)
OSS_ENABLED=${2:-false}  # 是否启用OSS上传

# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m' # No Color

log() {
    echo -e "${GREEN}[$(date '+%Y-%m-%d %H:%M:%S')]${NC} $1"
}

warn() {
    echo -e "${YELLOW}[警告]${NC} $1"
}

error() {
    echo -e "${RED}[错误]${NC} $1"
}

load_oss_config() {
    local config_file="$CONFIG_DIR/oss_config"
    if [ -f "$config_file" ]; then
        source "$config_file"
        return 0
    else
        warn "OSS配置文件不存在: $config_file"
        return 1
    fi
}

# 磁盘保护检查
check_disk_usage() {
    local usage=$(df "$BASE_DIR" | awk 'NR==2 {print $5}' | sed 's/%//')
    if [ $usage -ge $MAX_DISK_USAGE ]; then
        error "磁盘使用率过高: ${usage}% (超过 ${MAX_DISK_USAGE}%)"
        return 1
    fi
    return 0
}

# 清理旧日志
cleanup_old_logs() {
    log "清理旧日志文件..."
    
    # 清理temp目录
    rm -rf $TEMP_DIR/*
    
    # 清理超过1天的日志
    find $LOG_DIR -name "*.pcap" -mtime +1 -delete 2>/dev/null || true
    find $LOG_DIR -name "*.log" -mtime +1 -delete 2>/dev/null || true
    find $ARCHIVE_DIR -name "*.tar.gz" -mtime +7 -delete 2>/dev/null || true
    
    # 如果日志目录总大小超过2GB，清理最旧的文件
    local total_size=$(du -s $LOG_DIR 2>/dev/null | cut -f1 || echo 0)
    if [ $total_size -gt 2000000 ]; then  # 2GB in KB
        warn "日志目录过大(${total_size}KB)，清理最旧文件"
        find $LOG_DIR -name "*.pcap" -type f 2>/dev/null | xargs ls -tr 2>/dev/null | head -5 | xargs rm -f 2>/dev/null || true
    fi
}

# 资源监控函数
start_resource_monitor() {
    local monitor_pid=$1
    log "启动资源监控..."
    
    nohup bash -c "
    RESOURCE_MONITOR_PID=\$$
    echo \"RESOURCE_MONITOR_PID=\$RESOURCE_MONITOR_PID\" >> $TEMP_DIR/monitor_pids.txt
    
    while [ -f $TEMP_DIR/monitor_running.flag ] && kill -0 $monitor_pid 2>/dev/null; do
        echo \"=== \$(date) ===\" >> $LOG_DIR/resource_usage_$TIMESTAMP.log
        echo \"系统负载: \$(uptime)\" >> $LOG_DIR/resource_usage_$TIMESTAMP.log
        echo \"磁盘使用: \$(df -h $BASE_DIR | awk 'NR==2')\" >> $LOG_DIR/resource_usage_$TIMESTAMP.log
        
        # 监控tcpdump进程资源
        if ps -p $monitor_pid > /dev/null 2>/dev/null; then
            echo \"tcpdump资源使用:\" >> $LOG_DIR/resource_usage_$TIMESTAMP.log
            ps -p $monitor_pid -o pid,ppid,pcpu,pmem,rss,vsz,cmd 2>/dev/null >> $LOG_DIR/resource_usage_$TIMESTAMP.log
        fi
        
        # 监控网络连接数
        echo \"当前连接数: \$(netstat -an 2>/dev/null | grep -E ':80|:443' | wc -l)\" >> $LOG_DIR/resource_usage_$TIMESTAMP.log
        echo \" Established连接: \$(netstat -an 2>/dev/null | grep -E ':80|:443' | grep ESTABLISHED | wc -l)\" >> $LOG_DIR/resource_usage_$TIMESTAMP.log
        
        echo \"\" >> $LOG_DIR/resource_usage_$TIMESTAMP.log
        sleep 30
    done
    log \"资源监控进程退出\"
    " > /dev/null 2>&1 &
    
    echo $!  # 返回资源监控进程PID
}

# 生成唯一实例标识符
get_instance_id() {
    # 尝试获取ECS实例ID（适用于阿里云）
    if curl -s --connect-timeout 2 http://100.100.100.200/latest/meta-data/instance-id > /dev/null 2>&1; then
        INSTANCE_ID=$(curl -s http://100.100.100.200/latest/meta-data/instance-id 2>/dev/null)
    # 尝试获取其他云厂商的实例ID
    elif curl -s --connect-timeout 2 http://169.254.169.254/latest/meta-data/instance-id > /dev/null 2>&1; then
        INSTANCE_ID=$(curl -s http://169.254.169.254/latest/meta-data/instance-id 2>/dev/null)
    else
        # 如果无法获取云厂商实例ID，使用主机名+MAC地址生成唯一ID
        LOCAL_IP=$(hostname -I | awk '{print $1}')
        MAC_ADDR=$(cat /sys/class/net/$(ip route show default 2>/dev/null | awk '/default/ {print $5}' 2>/dev/null)/address 2>/dev/null | tr -d ':' | tail -c 6 2>/dev/null || echo "unknown")
        INSTANCE_ID="ecs-${LOCAL_IP//./-}-${MAC_ADDR}"
    fi
    echo "$INSTANCE_ID"
}

# OSS上传函数
upload_to_oss() {
    local file_path=$1
    
    if [ "$OSS_ENABLED" = "true" ]; then
        # 直接使用 oss_uploader.sh 进行上传，它会处理所有配置
        if $SCRIPTS_DIR/oss_uploader.sh upload "$file_path"; then
            log "OSS上传成功: $file_path"
            return 0
        else
            warn "OSS上传失败: $file_path"
            return 1
        fi
    else
        log "OSS上传未启用，跳过文件: $file_path"
        return 1
    fi
}

# 自动日志切分函数
start_log_rotation() {
    local base_name=$1
    local max_size_mb=$MAX_LOG_SIZE
    
    # 确保目录存在
    mkdir -p $PCAPS_DIR
    
    # 直接启动tcpdump，利用其内置的切分功能
    log "启动tcpdump监控，日志切分大小: ${max_size_mb}MB"
    tcpdump -i any -s 0 -w "$PCAPS_DIR/${base_name}_part.pcap" -C $max_size_mb -W 100 'tcp port 80 or tcp port 443' 2>/dev/null &
    local tcpdump_pid=$!
    
    # 等待tcpdump启动
    sleep 2
    if ! kill -0 $tcpdump_pid 2>/dev/null; then
        error "tcpdump启动失败，请检查权限和接口"
        return 1
    fi
    
    # 启动一个单独的进程来处理切分后的文件
    nohup bash -c "
    ROTATION_HANDLER_PID=\$$
    echo \"ROTATION_HANDLER_PID=\$ROTATION_HANDLER_PID\" >> $TEMP_DIR/monitor_pids.txt
    
    while [ -f $TEMP_DIR/monitor_running.flag ] && kill -0 $tcpdump_pid 2>/dev/null; do
        # 查找需要处理的.pcap文件（创建时间超过1分钟且未压缩）
        find $PCAPS_DIR -name \"${base_name}_part*.pcap\" -mmin +1 2>/dev/null | while read file; do
            if [ -f \"\$file\" ] && [[ \"\$file\" != *.gz ]]; then
                log \"处理切分文件: \$(basename \$file)\"
                if gzip \"\$file\"; then
                    upload_to_oss \"\${file}.gz\"
                    # 上传成功后删除本地压缩文件（如果配置了删除）
                    if [ \"\$DELETE_AFTER_UPLOAD\" = \"true\" ] || [ \"$DELETE_AFTER_UPLOAD\" = \"true\" ]; then
                        rm -f \"\${file}.gz\"
                    fi
                else
                    warn \"压缩文件失败: \$file\"
                fi
            fi
        done
        sleep 30
    done
    log \"日志切分处理进程退出\"
    " > /dev/null 2>&1 &
    
    echo $tcpdump_pid  # 返回tcpdump进程PID
}

# 停止所有监控进程
stop_all_monitors() {
    log "停止所有监控进程..."
    
    # 移除运行标志文件
    rm -f $TEMP_DIR/monitor_running.flag
    
    # 给进程一些时间自然退出
    sleep 2
    
    # 从PID文件停止进程
    if [ -f $TEMP_DIR/monitor_pids.txt ]; then
        while IFS= read -r line; do
            pid_name=$(echo $line | cut -d'=' -f1)
            pid=$(echo $line | cut -d'=' -f2)
            
            if kill -0 $pid 2>/dev/null; then
                log "停止进程 $pid_name: $pid"
                kill $pid 2>/dev/null || true
            fi
        done < $TEMP_DIR/monitor_pids.txt
    fi
    
    # 确保所有tcpdump进程停止
    pkill -f "tcpdump.*port (80|443)" 2>/dev/null || true
    pkill -f "netstat.*:80" 2>/dev/null || true
    
    # 等待进程完全停止
    sleep 3
    
    # 清理PID文件
    rm -f $TEMP_DIR/monitor_pids.txt
}

# 主监控函数
main() {
    log "=============================================="
    log "   增强版流量监控启动"
    log "   时间: $(date)"
    log "   监控时长: $DURATION 秒 ($(($DURATION/3600)) 小时)"
    log "   OSS上传: $OSS_ENABLED"
    log "=============================================="

    # 创建运行标志文件
    echo "running" > $TEMP_DIR/monitor_running.flag

    # 前置检查
    if ! check_disk_usage; then
        error "磁盘空间不足，监控终止"
        rm -f $TEMP_DIR/monitor_running.flag
        exit 1
    fi

    # 清理旧日志
    cleanup_old_logs

    # 停止之前的监控进程
    log "清理旧监控进程..."
    stop_all_monitors
    sleep 2

    # 创建必要的目录
    mkdir -p $LOG_DIR/{reports,pcaps,connections}

    # 记录监控信息
    cat > $LOG_DIR/monitor_info_$TIMESTAMP.txt << EOF
监控开始时间: $(date)
监控时长: $DURATION 秒
网络接口: $INTERFACE
最大日志大小: ${MAX_LOG_SIZE}MB
最大磁盘使用率: ${MAX_DISK_USAGE}%
OSS上传: $OSS_ENABLED
主机名: $(hostname)
EOF

    # 启动自动日志切分的监控
    log "启动自动日志切分监控..."
    ROTATION_PID=$(start_log_rotation "traffic_$TIMESTAMP")
    if [ $? -ne 0 ] || [ -z "$ROTATION_PID" ]; then
        error "日志切分监控启动失败"
        rm -f $TEMP_DIR/monitor_running.flag
        exit 1
    fi
    
    # 启动实时HTTP请求解析（不写大文件，只用于实时查看）
    log "启动实时请求解析..."
    nice -n 10 tcpdump -i any -A -s 0 'tcp port 80 and (tcp[((tcp[12:1] & 0xf0) >> 2):4] = 0x47455420)' 2>/dev/null | \
        grep -E "(GET|POST|PUT|DELETE|HEAD|OPTIONS|PATCH) |Host: " > $LOG_DIR/reports/http_requests_realtime_$TIMESTAMP.log &
    REQ_PID=$!

    # 启动连接状态监控
    log "启动连接状态监控..."
    nohup bash -c "
    CONNECTION_MONITOR_PID=\$$
    echo \"CONNECTION_MONITOR_PID=\$CONNECTION_MONITOR_PID\" >> $TEMP_DIR/monitor_pids.txt
    
    while [ -f $TEMP_DIR/monitor_running.flag ]; do
        echo \"=== \$(date) ===\" >> $LOG_DIR/connections/connections_$TIMESTAMP.log
        netstat -an 2>/dev/null | grep -E \":80|:443\" >> $LOG_DIR/connections/connections_$TIMESTAMP.log
        echo \"总连接数: \$(netstat -an 2>/dev/null | grep -E ':80|:443' | wc -l)\" >> $LOG_DIR/connections/connections_count_$TIMESTAMP.log
        echo \"ESTABLISHED: \$(netstat -an 2>/dev/null | grep -E ':80|:443' | grep ESTABLISHED | wc -l)\" >> $LOG_DIR/connections/connections_established_$TIMESTAMP.log
        sleep 10
    done
    log \"连接监控进程退出\"
    " > /dev/null 2>&1 &
    CONN_PID=$!

    # 启动资源监控（监控自动切分进程）
    log "启动资源监控..."
    RESOURCE_PID=$(start_resource_monitor $ROTATION_PID)

    # 记录所有进程PID
    {
        echo "ROTATION_PID=$ROTATION_PID"
        echo "REQ_PID=$REQ_PID" 
        echo "CONN_PID=$CONN_PID"
        echo "RESOURCE_PID=$RESOURCE_PID"
    } > $TEMP_DIR/monitor_pids.txt

    log "所有监控进程已启动:"
    log "  日志切分: $ROTATION_PID"
    log "  请求解析: $REQ_PID"
    log "  连接监控: $CONN_PID"
    log "  资源监控: $RESOURCE_PID"
    log ""
    log "监控进行中... 持续 $DURATION 秒"
    log "实时查看: tail -f $LOG_DIR/reports/http_requests_realtime_$TIMESTAMP.log"
    log "资源监控: tail -f $LOG_DIR/resource_usage_$TIMESTAMP.log"
    log ""
    log "如需提前停止: $SCRIPTS_DIR/stop.sh 或 Ctrl+C"
    log "查看状态: $SCRIPTS_DIR/ctl.sh status"

    # 等待监控时长
    local elapsed=0
    while [ $elapsed -lt $DURATION ] && [ "$MONITOR_RUNNING" = "true" ]; do
        # 每分钟检查一次磁盘空间
        if [ $((elapsed % 60)) -eq 0 ]; then
            if ! check_disk_usage; then
                warn "磁盘空间不足，提前停止监控"
                MONITOR_RUNNING=false
                break
            fi
        fi
        
        # 检查关键进程是否存活
        if ! kill -0 $ROTATION_PID 2>/dev/null; then
            error "主监控进程异常退出，停止监控"
            MONITOR_RUNNING=false
            break
        fi
        
        sleep 10
        elapsed=$((elapsed + 10))
        
        # 每5分钟显示一次进度
        if [ $((elapsed % 300)) -eq 0 ]; then
            local remaining=$((DURATION - elapsed))
            log "监控进行中... 已运行: $(($elapsed/60))分钟, 剩余: $(($remaining/60))分钟"
        fi
        
        # 短时间监控时更频繁地显示进度
        if [ $DURATION -le 600 ] && [ $((elapsed % 60)) -eq 0 ]; then
            local remaining=$((DURATION - elapsed))
            log "监控进度: ${elapsed}/${DURATION} 秒 (剩余: ${remaining}秒)"
        fi
    done

    if [ "$MONITOR_RUNNING" = "false" ]; then
        log "监控被手动停止"
    else
        log "监控时长到达，停止监控..."
    fi
    
    # 停止所有监控进程
    stop_all_monitors
    
    # 归档当前日志
    TIMESTAMP=$(date +%Y%m%d_%H%M%S)
    if [ "$(ls -A $LOG_DIR 2>/dev/null)" ]; then
        log "归档监控日志..."
        tar -czf $ARCHIVE_DIR/monitor_$TIMESTAMP.tar.gz -C $LOG_DIR . 2>/dev/null && {
            log "日志已归档到: $ARCHIVE_DIR/monitor_$TIMESTAMP.tar.gz"
            
            # 生成最终报告
            $SCRIPTS_DIR/generate_final_report.sh $TIMESTAMP
        } || warn "日志归档失败"
    fi

    # 清理临时文件
    rm -rf $TEMP_DIR/*
    log "增强版监控已完全停止！"
}

main "$@"
